package com.tanhua.mongo.api;

/**
 * @Author: cl
 * @Date: 2022/5/4 - 05 - 04
 * @Description:
 */

import cn.hutool.core.collection.CollUtil;
import com.tanhua.dubbo.api.MovementApi;
import com.tanhua.model.mongo.Friend;
import com.tanhua.model.mongo.Movement;
import com.tanhua.model.mongo.MovementTimeLine;
import com.tanhua.model.vo.PageResult;
import com.tanhua.mongo.service.TimeLineService;
import com.tanhua.mongo.utils.IdWorker;
import org.apache.dubbo.config.annotation.DubboService;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import java.util.ArrayList;
import java.util.List;

/**
 * 朋友圈动态模块
 */
@DubboService
public class MovementApiImpl implements MovementApi {

    @Autowired
    private MongoTemplate mongoTemplate;

    //pid自增工具类
    @Autowired
    private IdWorker idWorker;

    //异步处理
    @Autowired
    private TimeLineService timeLineService;


    /**
     * 发送朋友圈动态
     *
     * @param movement
     * @return
     */
    @Override
    public String send(Movement movement) {
        //1、保存动态到动态表
        //设置pid
        Long pid = idWorker.getNextId("movement");
        movement.setPid(pid);
        //设置时间
        movement.setCreated(System.currentTimeMillis());
        //保存数据
        mongoTemplate.save(movement);
        //2、查询朋友关系(好友id)   使用异步处理
//        Criteria criteria = Criteria.where("userId").is(movement.getUserId());
//        Query query = Query.query(criteria);
//        List<Friend> friends = mongoTemplate.find(query, Friend.class);
//        //3、保存到时间表线数据表(循环查询朋友的id)(因为数据太多，用异步，可以开启新的线程)
//        if (!CollUtil.isEmpty(friends)){
//            for (Friend friend : friends) {
//                MovementTimeLine movementTimeLine = new MovementTimeLine();
//                movementTimeLine.setMovementId(movement.getId());
//                movementTimeLine.setUserId(friend.getUserId());
//                movementTimeLine.setFriendId(friend.getFriendId());
//                movementTimeLine.setCreated(System.currentTimeMillis());
//                mongoTemplate.save(movementTimeLine);
//            }
//        }
        //2、使用异步处理查询好友关系并保存时间线表
        timeLineService.saveTimeLine(movement.getUserId(), movement.getId());
        return movement.getId().toHexString();
    }

    /**
     * 获取个人动态
     *
     * @param userId
     * @return
     */
    @Override
    public List<Movement> getByUserid(Long userId, Integer page, Integer pageSize) {
        //1、根据用户id查询动态表(movement)获取动态
        Criteria criteria = Criteria.where("userId").is(userId).and("state").in(new Integer[]{0, 1});
        Query query = Query.query(criteria)
                .skip((page - 1) * pageSize).limit(pageSize).with(Sort.by(Sort.Order.desc("created")));
        List<Movement> movements = mongoTemplate.find(query, Movement.class);
        return movements;
    }

    /**
     * 获取好友动态
     *
     * @param userId
     * @return
     */
    @Override
    public List<Movement> getByFriend(Long userId, Integer page, Integer pageSize) {
        //1、查询时间线表获取动态的id(当前用户id作为时间线表中的朋友id)
        Query query = Query.query(Criteria.where("friendId").is(userId));
        List<MovementTimeLine> movementTimeLines = mongoTemplate.find(query, MovementTimeLine.class);
        return getMovementsForFriend(movementTimeLines, page, pageSize);
    }

    /**
     * 查询好友可见动态(提取的公共方法)
     *
     * @param movementTimeLines
     * @return
     */
    private List<Movement> getMovementsForFriend(List<MovementTimeLine> movementTimeLines, Integer page, Integer pageSize) {
        //2、获取到动态的id判断是否为空，不为空说明有动态，查动态表获取动态
        List<Movement> m = new ArrayList<>();
        if (CollUtil.isEmpty(movementTimeLines)) {
            return m;
        }

        //将集合中的动态id通过工具类获取
        List<ObjectId> movementId = CollUtil.getFieldValues(movementTimeLines, "movementId", ObjectId.class);
        Criteria criteria = Criteria.where("id").in(movementId);
        Query q = Query.query(criteria)
                .skip((page - 1) * pageSize).limit(pageSize).with(Sort.by(Sort.Order.desc("created")));

        //3、查询动态表
        m = mongoTemplate.find(q, Movement.class);

        //3、返回动态数据
        return m;
    }

    /**
     * 通过推荐的pids查询动态
     *
     * @param pids
     * @return
     */
    @Override
    public List<Movement> findByPids(List<Long> pids) {

        //1、构建条件
        Query query = Query.query(Criteria.where("pid").in(pids)).with(Sort.by(Sort.Order.desc("created")));
        //2、查询动态表
        List<Movement> movements = mongoTemplate.find(query, Movement.class);
        return movements;
    }

    /**
     * 随机查询count条动态
     *
     * @param count
     * @return
     */
    @Override
    public List<Movement> findByRandom(Integer count) {

        //1、创建统计对象，设置统计参数
        TypedAggregation aggregation =//表示统计哪一个表中的几条数据
                Aggregation.newAggregation(Movement.class, Aggregation.sample(count));
        //2、调用mongoTemplate方法统计
        AggregationResults<Movement> results = mongoTemplate.aggregate(aggregation, Movement.class);
        //3、获取结果
        List<Movement> movements = results.getMappedResults();
        return movements;
    }

    /**
     * 通过动态id查询动态
     *
     * @param movementId
     * @return
     */
    @Override
    public Movement findByMovementId(String movementId) {
        Query query = Query.query(Criteria.where("id").is(movementId));
        Movement m = mongoTemplate.findOne(query, Movement.class);
        return m;
    }

    /**
     * 查询好友可见动态或者推荐好友所有动态
     *
     * @param userId
     * @return
     */
    @Override
    public List<Movement> getByFriendId(Long userId, Long friendId, Integer page, Integer pageSize) {
        //1、查询好有关系
        Query query = Query.query(Criteria.where("userId").is(userId).and("friendId").is(friendId));
        List<Friend> friends = mongoTemplate.find(query, Friend.class);
        //2、判断是好友还是推荐
        List<Movement> movements = new ArrayList<>();
        if (CollUtil.isEmpty(friends)) {
            //3、推荐查看所有
            Criteria criteria = Criteria.where("userId").is(friendId);
            Query query1 = Query.query(criteria)
                    .skip((page - 1) * pageSize).limit(pageSize).with(Sort.by(Sort.Order.desc("created")));
            movements = mongoTemplate.find(query1, Movement.class);
        } else {
            //4、好友查询可见
            Query query2 = Query.query(Criteria.where("friendId").is(userId).and("userId").is(friendId));
            List<MovementTimeLine> movementTimeLines = mongoTemplate.find(query2, MovementTimeLine.class);
            //调用公用方法获取动态(好友可见动态)
            movements = getMovementsForFriend(movementTimeLines, page, pageSize);
        }
        return movements;
    }

    /**
     * 根据用户的id或审核状态分页查询用户所有动态
     *
     * @param page
     * @param pagesize
     * @param uid
     * @param state
     * @return
     */
    @Override
    public PageResult getMovementByUidAndState(Integer page, Integer pagesize, Long uid, String state) {

        //1、构造条件
        Query query = new Query();
        if (uid != null) {
            query.addCriteria(Criteria.where("userId").is(uid));
        }
        if (state != null) {
            query.addCriteria(Criteria.where("state").is(Integer.parseInt(state)));
        }
        //2、查询总条数
        long count = mongoTemplate.count(query, Movement.class);
        //3、查询动态详情
        List<Movement> movements = mongoTemplate.find(query.skip((page - 1) * pagesize).limit(pagesize)
                        .with(Sort.by(Sort.Order.desc("created"))),
                Movement.class);

        return new PageResult(page, pagesize, count, movements);
    }

    /**
     * 更新动态审核状态
     *
     * @param movementId
     * @param state
     */
    @Override
    public void update(String movementId, Integer state) {

        Query query = Query.query(Criteria.where("id").is(movementId));

        Update update = Update.update("state", state);

        mongoTemplate.updateFirst(query, update, Movement.class);
    }
}
